home *** CD-ROM | disk | FTP | other *** search
- /*
- * Routines for sampling from Soundblaster 8-bit soundcards
- * These routines require the SB functions and DMA functions written
- * by Heath I. Hunnicutt. The required functions are included here.
- * Copyright (C) 1997 Philip VanBaren & Emil Laurentiu
- * Last modified: Wednesday, 06 August 1997
- */
-
- #include "freq.h"
-
- #ifdef SC_SB8
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #include <dos.h>
- #include <graphics.h>
- #include "sb.h"
- #include "sbio.h"
- #include "extern.h"
-
- /* Function prototypes */
- unsigned int sbpro_get_line_level( void );
- unsigned int sbpro_get_cd_level( void );
- unsigned int sbpro_get_mic_level( void );
- int atox( char *ptr );
- void far interrupt SBHandler( void );
- void init_sb8( char **environ );
- void reset_sb8( void );
- void halt_sb8( void );
- void cleanup_sb8( void );
- void recordblock_sb8( void far * buffer );
- void set_mixer_sb8( int mix, int level );
-
- unsigned int
- sbpro_get_line_level( void )
- {
- unsigned int val;
-
- outportb( sb_addr + 4, 0x2E );
- val = inportb( sb_addr + 5 );
- return ( ( ( val & 0x0F ) + ( val / 16 ) ) * 100 / 32 );
- }
-
- unsigned int
- sbpro_get_cd_level( void )
- {
- unsigned int val;
-
- outportb( sb_addr + 4, 0x28 );
- val = inportb( sb_addr + 5 );
- return ( ( ( val & 0x0F ) + ( val / 16 ) ) * 100 / 32 );
- }
-
- unsigned int
- sbpro_get_mic_level( void )
- {
- unsigned int val;
-
- outportb( sb_addr + 4, 0x0A );
- val = inportb( sb_addr + 5 );
- return ( ( val & 0x07 ) * 100 / 8 );
- }
-
- int
- atox( char *ptr )
- {
- // Convert ascii hex values to integer
- int v = 0;
-
- while ( ( ( *ptr >= '0' ) && ( *ptr <= '9' ) ) || ( ( ( *ptr | 0x20 ) >= 'a' ) && ( ( *ptr | 0x20 ) <= 'f' ) ) )
- {
- v = v * 16;
- if ( *ptr <= '9' )
- v = v + *ptr - '0';
- else
- v = v + ( *ptr | 0x20 ) - 'a' + 10;
- ptr++;
- }
- return v;
- }
-
- #define is_blaster(var) ((((var)[0]=='B')||((var)[0]=='b')) && \
- (((var)[1]=='L')||((var)[1]=='l')) && \
- (((var)[2]=='A')||((var)[2]=='a')) && \
- (((var)[3]=='S')||((var)[3]=='s')) && \
- (((var)[4]=='T')||((var)[4]=='t')) && \
- (((var)[5]=='E')||((var)[5]=='e')) && \
- (((var)[6]=='R')||((var)[6]=='r')))
-
- void far interrupt( *OldIRQ ) ( );
-
- /* Interrupt handler for DMA complete IRQ from Soundblaster */
- void far interrupt
- SBHandler( )
- {
- flag[record_buffer] = 1;
- if ( ++record_buffer >= BUFFERS )
- record_buffer = 0;
- inportb( DSP_DATA_AVAIL );
- outportb( 0x20, 0x20 );
- }
-
- void
- init_sb8( char **environ )
- {
- int i;
- unsigned char tm, im;
- long timeout;
-
- /* Scan the environment variables for BLASTER=Axxx Ix Dx */
- for ( i = 0; environ[i] != NULL; i++ )
- {
- if ( is_blaster( environ[i] ) )
- {
- int j;
- DOUT( "SB8: Found BLASTER environment variable." );
- for ( j = 8; environ[i][j] != 0; j++ )
- {
- if ( ( environ[i][j] == 'A' ) || ( environ[i][j] == 'a' ) )
- sb_addr = atox( &environ[i][j + 1] );
- if ( ( environ[i][j] == 'D' ) || ( environ[i][j] == 'd' ) )
- sb_dma = atoi( &environ[i][j + 1] );
- if ( ( environ[i][j] == 'I' ) || ( environ[i][j] == 'i' ) )
- sb_irq = atoi( &environ[i][j + 1] );
- // Skip to the next parameter
- while ( ( environ[i][j] != ' ' ) && ( environ[i][j + 1] != 0 ) )
- j++;
- }
- break;
- }
- }
- #ifdef DEBUG_OUTPUT
- {
- char message[100];
- sprintf( message, "SB8: Address=0x%03x, DMA=%d, IRQ=%d", sb_addr, sb_dma, sb_irq );
- DOUT( message );
- }
- #endif
-
- if ( ( sb_dma < 0 ) || ( sb_dma > 3 ) )
- {
- puts( "Only SB DMA channels up to 3 are supported." );
- exit( 1 );
- }
- if ( ( sb_irq < 1 ) || ( sb_irq > 7 ) )
- {
- puts( "Only SB IRQs up to 7 are supported." );
- exit( 1 );
- }
- reset_soundcard = reset_sb8;
- halt_soundcard = halt_sb8;
- cleanup_soundcard = cleanup_sb8;
- recordblock = recordblock_sb8;
- sample_size = 8;
- mixers = 0;
-
- set_SB_address( sb_addr );
- #ifndef DEBUG_MODE
- if ( !dsp_reset( ) )
- {
- closegraph( );
- printf( "Soundblaster not found at 0x%04x\n", sb_addr );
- exit( 1 );
- }
- dsp_voice( 0 );
-
- /* Check if we can do mixers, and enable them, if so */
- timeout = 1000000L;
- /* Wait for bit 7 to be cleared, or for a timeout */
- while ( ( inportb( sb_addr + 0x0E ) & 0x80 ) && ( --timeout ) );
- outportb( sb_addr + 0x0C, 0xE1 ); /* Get DSP version number */
- timeout = 1000000L;
- /* Wait for bit 7 to be set, or for a timeout */
- while ( ( !( inportb( sb_addr + 0x0E ) & 0x80 ) ) && ( --timeout ) );
- i = inportb( sb_addr + 0x0A );/* Get the major version number */
- while ( ( !( inportb( sb_addr + 0x0E ) & 0x80 ) ) && ( --timeout ) );
- inportb( sb_addr + 0x0A ); /* Get the major version number */
-
- if ( i > 2 )
- {
- DOUT( "SB8: Found an SBPro or greater, mixers are available" );
- mixers = 1;
- set_mixer = set_mixer_sb8;
- mic_level = sbpro_get_mic_level( );
- ext_level = sbpro_get_line_level( );
- int_level = sbpro_get_cd_level( );
- DOUT( "SB8: Set Master volume & FM volume to maximum" );
- set_master_level( 0x0f );
- set_fm_level( 0x0f );
- }
-
- /*
- * Add the SB DMA interrupt handler in the interrupt chain
- */
- disable( );
- OldIRQ = getvect( 0x08 + sb_irq );
- setvect( 0x08 + sb_irq, SBHandler );
- im = inportb( 0x21 );
- tm = ~( 1 << sb_irq );
- outportb( 0x21, im & tm );
- enable( );
- #endif
- }
-
- void
- reset_sb8( void )
- {
- /*
- * Initialize Soundblaster stuff
- */
- int i, dsp_tc;
-
- #ifndef DEBUG_MODE
- /* Round sampling rate to a valid value for the SB card */
- i = floor( 1000000.0 / SampleRate + 0.5 );
- if ( i < 1 )
- i = 1;
- SampleRate = floor( 1000000.0 / ( double ) i + 0.5 );
- dsp_tc = 256 - i;
-
- DOUT( "SB8: Setting sampling rate" );
- dsp_time( dsp_tc );
-
- /*
- * Initialize the SB DMA channel
- */
- DOUT( "SB8: Resetting the DMA channel" );
- if ( dma_reset( sb_dma ) )
- {
- closegraph( );
- puts( "Error resetting SB DMA channel." );
- puts( dma_errlist[dma_errno] );
- cleanup_sb8( );
- exit( 1 );
- }
- // Reset the buffer pointers
- queue_buffer = 0; // Pointer to next buffer to be queued
- record_buffer = 0; // Pointer to next buffer to be filled
- process_buffer = 0; // Pointer to next buffer to be FFTed
-
- for ( i = 0; i < BUFFERS; i++ )
- flag[i] = 0;
- /*
- * This function starts the DMA process.
- */
- DOUT( "SB8: Starting the DMA recording process" );
- recordblock_sb8( buffer[queue_buffer] );
- if ( ++queue_buffer >= BUFFERS )
- queue_buffer = 0;
- #endif
- }
-
- void
- halt_sb8( void )
- {
- #ifndef DEBUG_MODE
- /* Shut down the DMA transfers */
- DOUT( "SB8: Stopping the DMA transfer" );
- disable( );
- dma_reset( sb_dma );
- dsp_reset( );
- enable( );
- #endif
- }
-
- void
- cleanup_sb8( void )
- {
- // Clean up the soundcard routines
-
- unsigned char im, tm;
-
- #ifndef DEBUG_MODE
- DOUT( "SB8: Cleaning up the soundcard setup" );
- disable( );
- dma_reset( sb_dma );
- dsp_reset( );
- Sb_FM_Reset( );
- /* Restore old IRQ vector */
- setvect( 0x08 + sb_irq, OldIRQ );
- im = inportb( 0x21 );
- tm = 1 << sb_irq;
- outportb( 0x21, im | tm );
- enable( );
- #endif
- }
-
- void
- recordblock_sb8( void far * buffer )
- {
- #ifndef DEBUG_MODE
- /*
- * Start recording a new buffer. For now we don't have queueing
- * capabilities for the SB
- */
- if ( dma_setup( sb_dma, buffer, fftlen, 0 ) )
- {
- closegraph( );
- printf( "Error in dma_setup(): %d\n", dma_errno );
- puts( dma_errlist[dma_errno] );
- cleanup_sb8( );
- exit( 1 );
- }
- if ( dma_errno != 0 )
- {
- closegraph( );
- puts( "DMA error" );
- puts( dma_errlist[dma_errno] );
- cleanup_sb8( );
- exit( 1 );
- }
- dsp_dma_prepare( 0, fftlen );
- #endif
- }
-
-
- void
- set_mixer_sb8( int mix, int level )
- {
- #ifndef DEBUG_MODE
- /*
- * Set a mixer level on the PAS16 card
- */
- level = level * 16 / 100;
- if ( level > 15 )
- level = 15;
-
- if ( mix == MIXER_EXT )
- {
- DOUT( "SB8: Setting the line mixer level" );
- level = level + level * 16;
- outportb( sb_addr + 4, 0x2e );
- outportb( sb_addr + 5, level );
- outportb( sb_addr + 4, 0x0C ); /* Select the line input */
- outportb( sb_addr + 5, 0x27 );
- }
- else if ( mix == MIXER_INT )
- {
- DOUT( "SB8: Setting the CD mixer level" );
- level = level + level * 16;
- outportb( sb_addr + 4, 0x28 );
- outportb( sb_addr + 5, level );
- outportb( sb_addr + 4, 0x0C ); /* Select the CD input */
- outportb( sb_addr + 5, 0x23 );
- }
- else if ( mix == MIXER_MIC )
- {
- DOUT( "SB8: Setting the microphone mixer level" );
- outportb( sb_addr + 4, 0x0a );
- outportb( sb_addr + 5, level / 2 );
- outportb( sb_addr + 4, 0x0C ); /* Select the mic input */
- outportb( sb_addr + 5, 0x21 );
- }
- #endif
- }
-
- #endif
-